{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "高数下25、26页"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "反过来，如果点 M不在曲线 C上，那么它不可能同时在两个曲面上，所以它的坐标不满足方程组(3-2)。因此，曲线 C可以用方程组(3-2)来表示。方程组(3-2)就叫做空间曲线 C 的方程，而曲线 C就叫做方程组(3-2)的图形。\n",
    "\n",
    "在本节和下一节里，我们将以向量为工具，在空间直角坐标系中讨论最简单的曲面和曲线--平面和直线。\n",
    "\n",
    "二、平面的点法式方程\n",
    "\n",
    "如果一非零向量垂直于一平面，这向量就叫做该平面的法线向量。容易知道，平面上的任一向量均与该平面的法线向量垂直。\n",
    "\n",
    "因为过空间一点可以作而且只能作一平面垂直于一已知直线，所以当平面II上一点 $M_{0}(x_{0}, y_{0}, z_{0})$ 和它的一个法线向量 $n=(A,B,C)$ 为已知时，平面 II 的位置就完全确定了。下面我们来建立平面 II 的方程。\n",
    "\n",
    "设 $M(x,y,z)$ 是平面 II 上的任一点（图8-30）。\n",
    "\n",
    "则向量 $\\overrightarrow{M_{0}M}$ 必与平面 II 的法线向量 $n$ 垂直，即它们的数量积等于零：\n",
    "\n",
    "$$\n",
    "n \\cdot \\overrightarrow{M_{0}M} = 0.\n",
    "$$\n",
    "\n",
    "因为 $n=(A, B, C), \\overrightarrow{M_{0}M}=(x-x_{0}, y-y_{0}, z-z_{0})$，所以有：                              \n",
    "\n",
    "$$\n",
    "A(x-x_{0})+B(y-y_{0})+C(z-z_{0})=0.\n",
    "$$\n",
    "\n",
    "这就是平面 II 上任一点 $M$ 的坐标 $x,y,z$ 所满足的方程。                           "
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "反过来，如果 $M(x,y,z)$ 不在平面 $II$ 上，那么向量 $\\overrightarrow{M_{0}M}$ 与法线向量 $n$ 不垂直，从而 $n \\cdot \\overrightarrow{M_{0}M} \n",
    "eq 0$，即不在平面 $II$ 上的点 $M$ 的坐标 $x,y,z$ 不满足方程（3-3）。\n",
    "\n",
    "由此可知，平面 $II$ 上的任一点的坐标 $x,y,z$ 都满足方程（3-3）；不在平面 $II$ 上的点的坐标都不满足方程（3-3）。这样，方程（3-3）就是平面 $II$ 的方程，而平面 $II$ 就是方程（3-3）的图形。因为方程（3-3）是由平面 $II$ 上的一点 $M_{0}(x_{0}, y_{0}, z_{0})$ 及它的一个法线向量 $n=(A,B,C)$ 确定的，所以方程（3-3）叫做平面的点法式方程。\n",
    "\n",
    "## 例1\n",
    "求过点 $(2,-3,0)$ 且以 $n=(1, -2, 3)$ 为法线向量的平面的方程。\n",
    "\n",
    "**解** 根据平面的点法方程 (3-3), 得所求平面的方程为\n",
    "\n",
    "$$\n",
    "(x-2)-2(y+3)+3z=0,\n",
    "$$\n",
    "即\n",
    "\n",
    "$$\n",
    "x-2y+3z-8=0.\n",
    "$$\n",
    "\n",
    "## 例2\n",
    "求过三点 $M_{1}(2, -1,4)$、$M_{2}(-1,3, -2)$ 和 $M_{3}(0,2,3)$ 的平面的方程。\n",
    "\n",
    "**解** 先找出这平面的法线向量 $n$。因为向量 $n$ 与向量 $M_{1}M_{2}$ 和 $\\bar{M}_{1}M_{3}$ 都垂直，而 $M_{1}M_{2}=(-3, 4, -6), M_{1}M_{3}=(-2, 3, -1)$，所以可取它们的向量积为 $n$，即 \n",
    "$$\n",
    "n=\\bar{M_{1}M_{2}}\\times \\bar{M_{1}M_{3}}=\\left |\\begin{matrix} i&j&k\\\\ -3&4&-6\\\\ -2&3&-1\\end{matrix} \\right |=14i+9j-k,\n",
    "$$\n",
    "根据平面的点法式方程 (3-3), 得所求平面的方程为\n",
    "\n",
    "$$\n",
    "14(x-2)+9(y+1)-(z-4)=0,\n",
    "$$\n",
    "即\n",
    "\n",
    "$$\n",
    "14x+9y-z-15=0.\n",
    "$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "平面方程为：X - 2*Y + 3*Z - 8\n",
      "点（2, -3, 0）是否满足平面方程：True\n",
      "点（2, -3, 0）是否满足另一个假设的平面方程：True\n"
     ]
    }
   ],
   "source": [
    "import sympy as sp\n",
    "\n",
    "# 定义符号变量\n",
    "X, Y, Z = sp.symbols('X Y Z')\n",
    "\n",
    "# 给定的点和向量\n",
    "point = sp.Matrix([2, -3, 0])\n",
    "normal_vector = sp.Matrix([1, -2, 3])\n",
    "\n",
    "# 计算平面方程（点法式）\n",
    "plane_equation = normal_vector.dot(sp.Matrix([X, Y, Z])) - normal_vector.dot(point)\n",
    "plane_equation_simplified = sp.simplify(plane_equation)\n",
    "\n",
    "# 打印平面方程\n",
    "print(f\"平面方程为：{plane_equation_simplified}\")\n",
    "\n",
    "# 验证点（2, -3, 0）是否满足平面方程\n",
    "point_satisfaction = plane_equation_simplified.subs({X: 2, Y: -3, Z: 0})\n",
    "print(f\"点（2, -3, 0）是否满足平面方程：{point_satisfaction == 0}\")\n",
    "\n",
    "# 验证另一个平面方程（假设与给定平面平行）\n",
    "another_plane_equation = X - 2*Y + 3*Z - 8\n",
    "point_satisfaction_another = another_plane_equation.subs({X: 2, Y: -3, Z: 0})\n",
    "print(f\"点（2, -3, 0）是否满足另一个假设的平面方程：{point_satisfaction_another == 0}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "法线向量n为：[14  9 -1]\n",
      "平面方程系数为：A=14, B=9, C=-1, D=-15\n",
      "平面方程为：14x + 9y + -1z + -15 = 0\n",
      "点M1([ 2 -1  4])是否在平面上：True\n",
      "点M2([-1  3 -2])是否在平面上：True\n",
      "点M3([0 2 3])是否在平面上：True\n"
     ]
    }
   ],
   "source": [
    "import numpy as np\n",
    "\n",
    "# 定义三个点的坐标\n",
    "M1 = np.array([2, -1, 4])\n",
    "M2 = np.array([-1, 3, -2])\n",
    "M3 = np.array([0, 2, 3])\n",
    "\n",
    "# 计算向量MM2和MM3\n",
    "MM2 = M2 - M1\n",
    "MM3 = M3 - M1\n",
    "\n",
    "# 计算法线向量n，即MM2和MM3的向量积\n",
    "n = np.cross(MM2, MM3)\n",
    "\n",
    "# 打印法线向量n\n",
    "print(f\"法线向量n为：{n}\")\n",
    "\n",
    "# 使用点法式方程验证平面方程\n",
    "# 选择点M1(2, -1, 4)代入平面方程\n",
    "# 平面方程为：n · (P - M1) = 0，其中P是平面上的任意一点，n是法线向量\n",
    "# 展开后得到：n_x * (x - 2) + n_y * (y + 1) + n_z * (z - 4) = 0\n",
    "# 将n的坐标值代入上式，得到平面方程\n",
    "\n",
    "# 由于n可能是非单位向量，我们需要先计算n的模长，然后将其标准化（可选步骤，但有助于理解）\n",
    "norm_n = np.linalg.norm(n)\n",
    "standardized_n = n / norm_n\n",
    "\n",
    "\n",
    "# 平面方程系数\n",
    "A, B, C = n\n",
    "\n",
    "# 常数项D，通过代入点M1计算得到\n",
    "D = -np.dot(n, M1)\n",
    "\n",
    "# 打印平面方程系数和常数项\n",
    "print(f\"平面方程系数为：A={A}, B={B}, C={C}, D={D}\")\n",
    "\n",
    "# 打印平面方程\n",
    "print(f\"平面方程为：{A}x + {B}y + {C}z + {D} = 0\")\n",
    "\n",
    "# 验证点M1, M2, M3是否满足平面方程（应该满足，因为它们是用来定义平面的点）\n",
    "def verify_point_on_plane(point, A, B, C, D):\n",
    "    return np.isclose(A * point[0] + B * point[1] + C * point[2] + D, 0)\n",
    "\n",
    "print(f\"点M1({M1})是否在平面上：{verify_point_on_plane(M1, A, B, C, D)}\")\n",
    "print(f\"点M2({M2})是否在平面上：{verify_point_on_plane(M2, A, B, C, D)}\")\n",
    "print(f\"点M3({M3})是否在平面上：{verify_point_on_plane(M3, A, B, C, D)}\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "class Plane:\n",
    "    def __init__(self, A, B, C, D):\n",
    "        self.A = A\n",
    "        self.B = B\n",
    "        self.C = C\n",
    "        self.D = D\n",
    "        self.normal_vector = (A, B, C)\n",
    "\n",
    "    def __str__(self):\n",
    "        return f\"Ax + By + Cz + D = 0\\nwhere A={self.A}, B={self.B}, C={self.C}, D={self.D}\"\n",
    "\n",
    "    def is_through_origin(self):\n",
    "        return self.D == 0\n",
    "\n",
    "    def is_parallel_to_x_axis(self):\n",
    "        return self.A == 0\n",
    "\n",
    "    def is_parallel_to_y_axis(self):\n",
    "        return self.B == 0\n",
    "\n",
    "    def is_parallel_to_z_axis(self):\n",
    "        return self.C == 0\n",
    "\n",
    "    def is_parallel_to_xy_plane(self):\n",
    "        return self.A == 0 and self.B == 0\n",
    "\n",
    "    def is_parallel_to_yz_plane(self):\n",
    "        return self.A == 0 and self.C == 0\n",
    "\n",
    "    def is_parallel_to_xz_plane(self):\n",
    "        return self.B == 0 and self.C == 0\n",
    "\n",
    "# 示例：表示一个平面及其法线向量\n",
    "example_plane = Plane(3, -4, 1, -9)\n",
    "print(example_plane)\n",
    "print(f\"法线向量: {example_plane.normal_vector}\")\n",
    "\n",
    "# 检查示例平面是否通过原点\n",
    "print(f\"是否通过原点: {example_plane.is_through_origin()}\")\n",
    "\n",
    "# 创建一个通过x轴和点(4, -3, -1)的平面\n",
    "# 由于平面通过x轴，法线向量垂直于x轴，即B和C不为0，A为0\n",
    "# 我们可以通过点法式方程来求解D，但这里我们直接给出一般形式\n",
    "# 假设法线向量为(0, 1, 1)（注意，法线向量不是唯一的）\n",
    "plane_through_x_axis = Plane(0, 1, 1, -4*(-3) - 1*(-1))  # 使用点(4, -3, -1)代入By + Cz + D = 0求解D\n",
    "print(\"\\n通过x轴和点(4, -3, -1)的平面:\")\n",
    "print(plane_through_x_axis)\n",
    "print(f\"是否平行于x轴: {plane_through_x_axis.is_parallel_to_x_axis()}\")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
